package com.cctc.juc.source.Athread.threadlocal.BFastThreadLocal;

import io.netty.util.internal.InternalThreadLocalMap;
import io.netty.util.internal.PlatformDependent;

/**
 * FastThreadLocal 是如何优化 JDK 内置的 ThreadLocal 性能问题（ThreadLocalMap 的创建性能开销和内存占用损耗）的呢？？？
 * Netty 提供的 FastThreadLocal 主要依赖于两个重要的类：FastThreadLocalThread 和 InternalThreadLocalMap。
 * 1. FastThreadLocalThread 类。该类继承自 Thread 原生了，并提供了一个扩展字段 InternalThreadLocalMap，用于替换 ThreadLocalMap，来存储线程本地变量数据。
 * 2. InternalThreadLocalMap 类。该类与 ThreadLocalMap 一样，都是用于存储线程本地变量数据，但是 InternalThreadLocalMap 直接使用 Object Set 数组代替了 Entry Map 数组，并为每个线程本地变量分配一个全局唯一索引 index，在读写数据时直接通过 index（数组下标）操作线程本地变量，时间复杂度为 O(1)。
 * 因此，只有 FastThreadLocal 和 FastThreadLocalThread 组合使用时，才能发挥出 FastThreadLocal 的性能优势。
 * 面试题：和 ThreadLocal 相比，FastThreadLocal 的优势有哪些？？？
 * 1. 高效查找和扩容。
 * - FastThreadLocal 可以直接根据数组下标 index 访问线程本地变量，时间复杂度为 O(1)；而 ThreadLocal 在数据较多时很容易发生哈希冲突，且 ThreadLocalMap 内部采用的是线性探测法（开放地址法）解决哈希冲突的，需要不停的向下寻找空闲位置，效率较低。
 * - FastThreadLocal 相比 ThreadLocal 扩容更加简单、高效。FastThreadLocal 以数组小标 index 为基准向上取整到 2 的次幂作为扩容容量，然后只需把原数据拷贝到新数组即可；而 ThreadLocal 内部采用的哈希表，所以在扩容时需要再做一轮 rehash，实现复杂且效率较低。
 * 2. 安全性更高。ThreadLocal 使用不当容易造成内存泄露问题，在使用线程池的场景下，只能通过主动回收的方式防止内存泄露；而 FastThreadLocal 不仅提供了 remove() 主动回收对象的方法，且还提供了一个 FastThreadLocalRunnable 包装方法，在任务执行完毕后会自动执行 removeAll() 方法，将所有的 FastThreadLocal 对象都清除掉。
 */
public class TFastThreadLocal<V> {
    // 线程局部变量索引：为每个线程本地变量分配一个全局唯一索引 index，在读写数据时直接通过 index（数组下标）操作线程本地变量，时间复杂度为 O(1)。
    private final int index = InternalThreadLocalMap.nextVariableIndex();

    // --- 核心方法 --- //

    protected V initialValue() throws Exception {
        return null;
    }

    public final V get() {
        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
        Object v = threadLocalMap.indexedVariable(this.index);
        return v != InternalThreadLocalMap.UNSET ? v : this.initialize(threadLocalMap);
    }

    public final void set(V value) {
        if (value != InternalThreadLocalMap.UNSET) {
            InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
            this.setKnownNotUnset(threadLocalMap, value);
        } else {
            this.remove();
        }
    }

    public final void remove() {
        this.remove(InternalThreadLocalMap.getIfSet());
    }

    public final void remove(InternalThreadLocalMap threadLocalMap) {
        if (threadLocalMap != null) {
            Object v = threadLocalMap.removeIndexedVariable(this.index);
            removeFromVariablesToRemove(threadLocalMap, this);
            if (v != InternalThreadLocalMap.UNSET) {
                try {
                    this.onRemoval(v);
                } catch (Exception var4) {
                    PlatformDependent.throwException(var4);
                }
            }

        }
    }


}
